package com.java.service;

import com.java.entity.vo.FileUploadResult;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.errors.MinioException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;

@Slf4j
@Service
public class MinioService {
    private static final String DATE_PATTERN = "yyyy/MM/dd";
    private static final String FILENAME_SEPARATOR = "-";

    @Resource
    private MinioClient minioClient;

    @Value("${minio.bucket}")
    private String bucket;

    @Value("${minio.external-url-prefix:}")
    private String externalUrlPrefix;

    public FileUploadResult uploadFile(MultipartFile file) {
        String fileOriginalFilename = file.getOriginalFilename();
        String originalFilename = sanitizeFilename(fileOriginalFilename);
        long fileSize = file.getSize();
        String objectName = buildObjectName(originalFilename);
        try (InputStream inputStream = file.getInputStream()) {
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(bucket)
                    .object(objectName)
                    .stream(inputStream, fileSize, -1)
                    .contentType(file.getContentType())
                    .build());
            String fileUrl = buildReturnUrl(objectName);
            return FileUploadResult.success(fileOriginalFilename,objectName, fileUrl);
        } catch (MinioException e) {
            log.error("MinIO存储异常，objectName:{}，errMsg:{}", objectName, e.getMessage(), e);
            throw new RuntimeException("文件上传存储异常", e);
        } catch (Exception e) {
            log.error("文件上传失败，objectName:{}，errMsg:{}", objectName, e.getMessage(), e);
            throw new RuntimeException("文件上传失败: " + e.getMessage(), e);
        }
    }

    /**
     * url转base64 不带拼接头
     * @param imageUrl
     * @return
     * @throws IOException
     */
    public String convertImageUrlToBase64Png(String imageUrl) throws IOException {
        // 从 URL 读取图片
        URL url = new URL(imageUrl);
        BufferedImage image = ImageIO.read(url);

        // 将图片转换为 PNG 格式的字节数组
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ImageIO.write(image, "png", outputStream);
        byte[] imageBytes = outputStream.toByteArray();

        // 将字节数组转换为 Base64 字符串
        return Base64.getEncoder().encodeToString(imageBytes);
    }

    /**
     * 上传base64格式的png图片到minio
     * @param base64String
     * @return
     */
    public FileUploadResult uploadBase64Image(String base64String) {
        // 生成文件名
        String objectName = generateImageObjectName();
        String contentType = "image/png"; // 强制使用 PNG ContentType

        try {
            // 解码 Base64 字符串
            byte[] fileBytes = Base64.getDecoder().decode(base64String);

            // 将字节数组转换为输入流
            try (InputStream inputStream = new ByteArrayInputStream(fileBytes)) {
                minioClient.putObject(PutObjectArgs.builder()
                        .bucket(bucket)
                        .object(objectName)
                        .stream(inputStream, fileBytes.length, -1)
                        .contentType(contentType)
                        .build());
                String fileUrl = buildReturnUrl(objectName);
                return FileUploadResult.success(objectName, objectName, fileUrl); // 原始文件名和对象名相同
            }

        } catch (MinioException e) {
            log.error("MinIO存储异常，objectName:{}，errMsg:{}", objectName, e.getMessage(), e);
            throw new RuntimeException("文件上传存储异常", e);
        } catch (Exception e) {
            log.error("文件上传失败，objectName:{}，errMsg:{}", objectName, e.getMessage(), e);
            throw new RuntimeException("文件上传失败: " + e.getMessage(), e);
        }
    }
    // 生成图片文件名
    private String generateImageObjectName() {
        String datePrefix = new SimpleDateFormat(DATE_PATTERN).format(new Date());
        String uuid = UUID.randomUUID().toString();
        String timestamp = String.valueOf(System.currentTimeMillis());
        return String.join("/", datePrefix,
                uuid + FILENAME_SEPARATOR + timestamp + FILENAME_SEPARATOR + Instant.now().toEpochMilli() + ".png"
        );
    }


    /** 构建对象名：yyyy/MM/dd/uuid-时间戳-原始文件名 */
    private String buildObjectName(String originalFilename) {
        String datePrefix = new SimpleDateFormat(DATE_PATTERN).format(new Date());
        String uuid = UUID.randomUUID().toString();
        String timestamp = String.valueOf(System.currentTimeMillis());
        return String.join("/", datePrefix,
                uuid + FILENAME_SEPARATOR + timestamp + FILENAME_SEPARATOR + originalFilename
        );
    }

    /** 文件名预处理：防止特殊字符或null */
    private String sanitizeFilename(String name) {
        if (name == null || name.trim().isEmpty()) {
            return "unknown";
        }
        // 替换掉空格、反斜杠、回车等特殊字符，保留常见文件名合法字符
        return name.replaceAll("[\\s\\\\/:*?\"<>|]", "_");
    }

    /** 组装返回外链URL */
    private String buildReturnUrl(String objectName) {
        if (externalUrlPrefix != null && !externalUrlPrefix.trim().isEmpty()) {
            return externalUrlPrefix + "/" + bucket + "/" + objectName;
        } else {
            return bucket + "/" + objectName;
        }
    }



}

